#include "YjlSet.h"             // 函入 程式庫系統設定 (先行標頭檔)
//#include "cFile.h"
//#include "FileSup.h"
#include "HuffPack.h"           // 函入 Huffman 壓縮支援程式
//#include "YjlDateTime.h"        // 函入 標準日期時間程式庫
//#include "cIniPaster.h"         // 函入 cIniPaster 參數資料剪貼物件
//#include "YjlStd.h"             // 函入 阿洲支援程式
#include <time.h>
#include "iniparser.h"

//#define DBG(fmt, ...) wprintf(L##fmt, ##__VA_ARGS__); fflush(stdout);
#define DBG(fmt, ...) do{}while(0)
void StringReplaceChar(wchar_t *str, wchar_t oldchr, wchar_t newchr);
// ■=== 預設定義 ==========================================================================================================
#define dFwMax          5               // 韌體種類最大數量
#define dFW_IMG_ID      0x55AAAA55      // 原廠 Panacom ID
#define dAlignSize      512             // 分界對齊大小
#define MathAlign(val)  ((val + (dAlignSize - 1)) & (~(dAlignSize - 1)))

// ■=== 結構定義 ==========================================================================================================
    #pragma pack(push, 1)               // 設定對齊為 1 Byte
    typedef struct     
    {
        U32     FirmwareID;                 // 韌體識別碼               dFW_IMG_ID
        U8      Version[12];                // 韌體版本                 FW_REVISION dDebugChar ("15.0.0D")      ==> Ini 檔案導入
        U8      BoardType[16];              // 適用主版型號             dStrMainType dStrFunType                ==> Ini 檔案導入
        U8      Language[16];               // 使用語系                 dStrLanguage                            ==> Ini 檔案導入 (可以取消)
        U8      CustomComp[24];             // 客製化公司名稱           dStrCompName                            ==> Ini 檔案導入 (可以取消)
        U8      ReleaseDate[16];            // 韌體出廠日期             __DATE__                                ==> 合併時候導入
        U8      ReleaseTime[12];            // 韌體出廠時間             __TIME__                                ==> 合併時候導入
        U32     CheckSum;                   // 檢查碼 (未壓縮版本)      0x00000000                              ==> 合併時候導入
        U32     TempData;                   // 檢查碼校正值             0xFFFFFFFF                              ==> 合併時候導入
        U32     DataTimeLowDWord;           // 韌體出廠時間值低 DWORD (由 MakeFwing 埋入)                       ==> 合併時候導入
        U32     DataTimeHighDWord;          // 韌體出廠時間值高 DWORD (由 MakeFwing 埋入)                       ==> 合併時候導入
        U32     XorU32Val;                  // XOR 運算數值
        U32     TotalSize;                  // 檔案總大小
        U32     DataOffset[dFwMax];         // 資料之偏移位置 (0=無)
        U32     DataPackSize[dFwMax];       // 壓縮後資料大小 (0=無)
        U32     DataUnPackSize[dFwMax];     // 未壓縮資料大小 (0=無)
    } sFWInfo;
    #pragma pack(pop)                   // 還原對齊

// ■=== 變數定義 ==========================================================================================================
    wchar_t *gIniFileName;                // 腳本檔案名稱
    wchar_t *gProgFileName = NULL;        // 韌體檔案名稱
    wchar_t *gWriteFileName;              // 輸出檔案名稱
    wchar_t *gSouFirmFileName[dFwMax];    // 來源之韌體資料
    BOOL   gPackFlag = FALSE;           // 是否使用壓縮
    sFWInfo gFwInfo;
    const char *MonthString[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
                                    "Jul", "Agu", "Sep", "Oct", "Nov", "Dec"};

    const wchar_t *ImgMode[] = {uni ("Boot"), uni ("Kernel"), uni ("RamDisk"), uni ("Jffs2"), uni ("Custom")};
    
// ■=== 程式開始 ==========================================================================================================
U32 GetCheckSum (void *tMemPtr, U32 tMemSize, U32 tStartOffset)
// 功能 : 計算 Check Sum 之數值
// 參數 : tMemPtr      = 要計算之記憶體起始位址
//      : tMemSize     = 要計算之記憶體大小
//        tStartOffset = 開始計算之偏移植
// 傳回 : Check Sum 之數值
{
    U32 sum;
    U8 *souptr, *endptr;

    souptr = ((U8*)tMemPtr) + tStartOffset;
    endptr = souptr + tMemSize;
    sum = 0;
    while (souptr < endptr) sum += *souptr++;
    return (sum);
}

void WriteCheckSum (sFWInfo *tFWInfo, U32 tMemSize)
// 功能 : 埋入 CheckSum 作業
// 參數 : tMemPtr    = 記憶體起始位址
//        tMemSize   = 使用之記憶體大小
//        tFWInfo = 額外 VXC 韌體資訊 (NULL = 無)
{
    U32 chksum;

    // 設定預設值
    tFWInfo->CheckSum = 0;
    tFWInfo->TempData = 0xFFFFFFFF;
    // 計算 chksum
    chksum = GetCheckSum ((U8*)tFWInfo, tMemSize, 0);
    // 埋入 自體 CheckSum
    tFWInfo->CheckSum = chksum;
    tFWInfo->TempData = 0xFFFFFFFF - chksum;
}

void *SearchMemoryString (void *tMemPtr, U32 tMemSize, char *tString)
// 功能 : 尋找記憶體中之字串
// 參數 : tMemPtr   = 記憶體起始位址
//        tMemSize  = 使用之記憶體大小
//        tString   = 要尋找之字串
// 傳回 : 成功 = 找到之記憶體位址
//        失敗 = NULL
{
    U32 i, len;
    char *memptr;

    len = strlen (tString);
    if (len == 0) return (NULL);
    tMemSize -= len;
    memptr = (char*) tMemPtr;
    for (i = 0; i < tMemSize; i++)
    {
        if (!strncasecmp (tString, (char*)(memptr + i), len))
        {
            return (memptr + i);
        }
    }
    return (NULL);
}

void ShowUsage(void)
{
	#if PRN == 1
    uni_printf (uni("┌─────────────────────────────────────┐\n"));
    uni_printf (uni("│   MakeFwing   轉換程式, Copyright by Lin Joy, %.11ls %.8ls       │\n"), __WDATE__, __WTIME__);
    uni_printf (uni("├─────────────────────────────────────┤\n"));
    uni_printf (uni("│命令格式 : MakeFwing.exe 腳本檔案 目的檔名                                │\n"));
    uni_printf (uni("│           目的檔名 = 要輸出之目的檔案名稱                                │\n"));
    uni_printf (uni("└─────────────────────────────────────┘\n"));
    #elif PRN == 2
    uni_printf (uni("┌──────────────────────────────────────────────────────────────────────────┐\n"));
    uni_printf (uni("│   MakeFwing   轉換程式, Copyright by Lin Joy, %.11ls %.8ls       │\n"), __WDATE__, __WTIME__);
    uni_printf (uni("├──────────────────────────────────────────────────────────────────────────┤\n"));
    uni_printf (uni("│命令格式 : MakeFwing.exe 腳本檔案 目的檔名                                │\n"));
    uni_printf (uni("│           目的檔名 = 要輸出之目的檔案名稱                                │\n"));
    uni_printf (uni("└──────────────────────────────────────────────────────────────────────────┘\n"));
    #else
    #error ERROR PRN!
    #endif
}

int main (int argc, char *argv[])
{
    U32 i, j, max, readsize, tolsize, lastnum, u32val, progsize, *u32ptr;
    U8 *workptr, *u8ptr;
    VOID *ptr, *progdata;
    VOID *soudata[dFwMax], *tardata[dFwMax];
    U32 sousize[dFwMax], tarsize[dFwMax];
    dictionary *ini;
    sFWInfo *fwsouinfo;
    TIMESTAMP_STRUCT timest={0};
    U64 timeval64;
    U32 timeval32;
    //==>
    wchar_t gProgFileName_buf[256];
    wchar_t gSouFirmFileName_buf[dFwMax][256];
    wchar_t IniFileName[256];
    wchar_t WriteFileName[256];
    setlocale(LC_ALL, LC);
    //<==

    if (argc <= 2)
    {
		ShowUsage();
        return (1);
    }
//  uni_printf (uni("Date = %s\n"), __DATE__);
//  uni_printf (uni("Time = %s\n"), __TIME__);
	DBG("111\n");
    // 變數設定
    MemZero (&gFwInfo, sizeof (sFWInfo));
    progdata = NULL;
    progsize = 0;
    for (i = 0; i < dFwMax; i++)
    {
        gSouFirmFileName[i] = NULL;
        soudata[i] = NULL;
        sousize[i] = 0;
        tardata[i] = NULL;
        tarsize[i] = 0;
    }
    lastnum = 0;                                // 最後有資料的編號 (不需要做 512 定位數量)
	DBG("222\n");
    // 取得外部引數
    mbstowcs(&IniFileName[0], argv[1], 256);
    gIniFileName = &IniFileName[0];        // 腳本檔案名稱
    
    mbstowcs(&WriteFileName[0], argv[2], 256);
    gWriteFileName = &WriteFileName[0];      // 輸出檔案名稱
	DBG("333\n");
    // 取得腳本資料
    ini = iniparser_load (/*gIniFileName*/argv[1]);
    DBG("444\n");
    // 載入 [Setup]
    if( iniparser_find_entry(ini, strdup("Setup")) ) //if ((ini->LabelReset (uni ("Setup")))
    {	
        // 韌體版本         最大 11 字元
        char *pstr = iniparser_getstring(ini, strdup("Setup:Version"), NULL);
        if(pstr) memcpy(gFwInfo.Version,   pstr, sizeof (gFwInfo.Version));    //ini->GetString (uni ("Version"), (wchar_t*)gFwInfo.Version, sizeof (gFwInfo.Version));
        DBG("gFwInfo.Version=%s\n", gFwInfo.Version);
        // 適用主版型號     最大 15 字元
        pstr = iniparser_getstring(ini, strdup("Setup:BoardType"), NULL);
        if(pstr) memcpy(gFwInfo.BoardType, pstr, sizeof (gFwInfo.BoardType));  //ini->GetString (uni ("BoardType"), (wchar_t*)gFwInfo.BoardType, sizeof (gFwInfo.BoardType));
        
        // 使用語系         最大 15 字元
        pstr = iniparser_getstring(ini, strdup("Setup:Language"), NULL);
        if(pstr) memcpy(gFwInfo.Language, pstr, sizeof (gFwInfo.Language));    //ini->GetString (uni ("Language"), (wchar_t*)gFwInfo.Language, sizeof (gFwInfo.Language));
       	
        // 客製化公司名稱   最大 23 字元
        pstr = iniparser_getstring(ini, strdup("Setup:CustomComp"), NULL);
        if(pstr) memcpy(gFwInfo.CustomComp, pstr, sizeof (gFwInfo.CustomComp));//ini->GetString (uni ("CustomComp"), (wchar_t*)gFwInfo.CustomComp, sizeof (gFwInfo.CustomComp));
        
        // XOR 運算數值
        pstr = iniparser_getstring(ini, strdup("Setup:XorU32Val"), NULL);
        gFwInfo.XorU32Val = strtoul(pstr, NULL, 16);//ini->GetValue32 (uni ("XorU32Val"));
        // 是否使用壓縮
        gPackFlag = iniparser_getint(ini, strdup("Setup:PackFlag"), -1);//ini->GetValue32 (uni ("PackFlag"));
        DBG("555, gPackFlag=%d, XorU32Val=0x%08X\n", gPackFlag, gFwInfo.XorU32Val);
    }
	
    // 載入 [Firmware]
    if( iniparser_find_entry(ini, strdup("Firmware")) ) //if (ini->LabelReset (uni ("Firmware")))
    {	DBG("666, XorU32Val=0x%08X\n", gFwInfo.XorU32Val);
        //gProgFileName = ini->GetAllocString (uni ("Program"));
        //for (i = 0; i < dFwMax; i++) gSouFirmFileName[i] = ini->GetAllocString (ImgMode[i]);
        char* pstr = iniparser_getstring(ini, strdup("Firmware:Program"), NULL);
        mbstowcs(&gProgFileName_buf[0], pstr, 256);
        gProgFileName = gProgFileName_buf;
        StringReplaceChar(gProgFileName, '\\', '/');
        for (i = 0; i < dFwMax; i++) 
        {
        	char section_name[32];
        	char mode[32];
        	char *pstr;
        	wcstombs(&mode[0], ImgMode[i], 32);
        	sprintf(section_name, "Firmware:%s", &mode[0]);
        	pstr = iniparser_getstring(ini, section_name, NULL);
        	mbstowcs(gSouFirmFileName_buf[i], pstr, 256);
        	gSouFirmFileName[i] = gSouFirmFileName_buf[i];
        	StringReplaceChar(gSouFirmFileName[i], '\\', '/');
        	DBG("777, XorU32Val=0x%08X, %ls\n", gFwInfo.XorU32Val, gSouFirmFileName[i]);
        }
        
    }

    // 設定 gFwInfo 資料結構
    gFwInfo.FirmwareID = dFW_IMG_ID;                                // 韌體識別碼               dFW_IMG_ID
    // 設定 韌體出廠時間值
    timeval64 = GetDateTimeByU64 ();
    gFwInfo.DataTimeLowDWord  = (timeval64 & 0xFFFFFFFF);           // 韌體出廠時間值低 DWORD (由 MakeFwing 埋入)
    gFwInfo.DataTimeHighDWord = ((timeval64 >> 32) & 0xFFFFFFFF);   // 韌體出廠時間值高 DWORD (由 MakeFwing 埋入)
    // 設定 韌體出廠日期 Jan 19 2010
    timeval32 = GetDateTimeByU32 ();
    ConvDateTime (timeval32, &timest);
    sprintf ((char*)gFwInfo.ReleaseDate, "%s %d %d", MonthString[timest.month - 1], timest.day, timest.year);
    // 設定 韌體出廠時間 時:分:秒
    GetTime ((wchar_t*)gFwInfo.ReleaseTime);
	
    // 載入韌體 參考檔
    if (gProgFileName && uni_strlen (gProgFileName))
    {	DBG("888, XorU32Val=0x%08X, DATE=%s, TIME=%s\n", gFwInfo.XorU32Val, gFwInfo.ReleaseDate, gFwInfo.ReleaseTime);
        readsize = 0;
        //ptr = FileOpenRead (gProgFileName, NULL, &readsize);
        //==>	
        FILE *fp;
        DBG("888-1\n");
        fp = wfopen(gProgFileName, "rb");
        DBG("888-2\n");
        fseek(fp, 0, SEEK_END);
        DBG("888-3\n");
        readsize = ftell(fp);
        DBG("888-4, %d\n", readsize);
        fseek(fp, 0, SEEK_SET);
        DBG("888-5, %d\n", readsize);
        ptr = malloc(readsize);
        DBG("888-6, %d\n", readsize);
        fread(ptr, 1, readsize, fp);
        DBG("888-7, %d\n", readsize);
        fclose(fp);
        //<==
        if (ptr)
        {	DBG("999\n");
            progdata = ptr;
            progsize = readsize;
        }
        else
        {	DBG("AAA\n");
            uni_printf (uni("錯誤，韌體檔案 '%ls' 沒有發現…\n"), gProgFileName);
            return (-1);
        }
    }
    if (progdata == NULL) gProgFileName = NULL;

    // 韌體來源參考檔案
    if (progdata)
    {	DBG("BBB\n");
        // 找出 fwsouinfo 之放置位置
        fwsouinfo = NULL;
        for (i = 0; i < progsize; i += 4)
        {
            if (*((U32*)((U8*)progdata + i)) == dFW_IMG_ID &&
                *((U8*)((U8*)progdata + i + 4)) == '1' && 
                *((U8*)((U8*)progdata + i + 5)) == '5')
            {
                fwsouinfo = (sFWInfo *)((U8*)progdata + i);
                break;
            }
        }
        if (fwsouinfo == NULL)
        {
            uni_printf (uni("錯誤，找不到 韌體資料 '0xAA55AA55' 標記位置…\n"));
            return (-1);
        }
        // 複製資料
        MemCopy (&gFwInfo.Version, &fwsouinfo->Version, sizeof (gFwInfo.Version));              // 韌體版本       Version
        MemCopy (&gFwInfo.BoardType, &fwsouinfo->BoardType, sizeof (gFwInfo.BoardType));        // 適用主版型號   BoardType
    //  MemCopy (&gFwInfo.Language, &fwsouinfo->Language, sizeof (gFwInfo.Language));           // 使用語系       Language
        MemCopy (&gFwInfo.CustomComp, &fwsouinfo->CustomComp, sizeof (gFwInfo.CustomComp));     // 客製化公司名稱 CustomComp
        MemCopy (&gFwInfo.ReleaseDate, &fwsouinfo->ReleaseDate, sizeof (gFwInfo.ReleaseDate));  // 韌體出廠日期   ReleaseDate
        MemCopy (&gFwInfo.ReleaseTime, &fwsouinfo->ReleaseTime, sizeof (gFwInfo.ReleaseTime));  // 韌體出廠時間   ReleaseTime

        // 轉換韌體出廠時間值 來自 fwsouinfo
        char tmpbuf[20];
        TIMESTAMP_STRUCT timest;

        // 轉換年
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseDate + 7, 4);
        tmpbuf[4] = 0;
        timest.year = atoi (tmpbuf);
        // 轉換月
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseDate + 0, 3);
        tmpbuf[3] = 0;
        if (!strcasecmp (tmpbuf, "Jan")) timest.month = 1;     //  1月 January
        if (!strcasecmp (tmpbuf, "Feb")) timest.month = 2;     //  2月 February
        if (!strcasecmp (tmpbuf, "Mar")) timest.month = 3;     //  3月 March
        if (!strcasecmp (tmpbuf, "Apr")) timest.month = 4;     //  4月 April
        if (!strcasecmp (tmpbuf, "May")) timest.month = 5;     //  5月 May
        if (!strcasecmp (tmpbuf, "Jun")) timest.month = 6;     //  6月 June
        if (!strcasecmp (tmpbuf, "Jul")) timest.month = 7;     //  7月 July
        if (!strcasecmp (tmpbuf, "Agu")) timest.month = 8;     //  8月 Aguest
        if (!strcasecmp (tmpbuf, "Sep")) timest.month = 9;     //  9月 September
        if (!strcasecmp (tmpbuf, "Oct")) timest.month = 10;    // 10月 October
        if (!strcasecmp (tmpbuf, "Nov")) timest.month = 11;    // 11月 November
        if (!strcasecmp (tmpbuf, "Dec")) timest.month = 12;    // 12月 Decembe
        // 轉換日
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseDate + 4, 2);
        tmpbuf[2] = 0;
        timest.day = atoi (tmpbuf);
        // 轉換時
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseTime + 0, 2);
        tmpbuf[2] = 0;
        timest.hour = atoi (tmpbuf);
        // 轉換分
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseTime + 3, 2);
        tmpbuf[2] = 0;
        timest.minute = atoi (tmpbuf);
        // 轉換秒
        strncpy (tmpbuf, (char*)fwsouinfo->ReleaseTime + 6, 2);
        tmpbuf[2] = 0;
        timest.second = atoi (tmpbuf);
        timest.fraction = 0;

        timeval64 = ConvDateTime (&timest, timeval64);
        gFwInfo.DataTimeLowDWord  = (timeval64 & 0xFFFFFFFF);
        gFwInfo.DataTimeHighDWord = ((timeval64 >> 32) & 0xFFFFFFFF);
		DBG("H=0x%08X, L=0x%08X\n", gFwInfo.DataTimeHighDWord, gFwInfo.DataTimeLowDWord);
    }
	
    // 釋放 Program 記憶體
    if (progdata)
    {
        MemFree (progdata);
        progdata = NULL;
    }
	
    // 載入取得來源所有檔案
    for (i = 0; i < dFwMax; i++)
    {	
        if (gSouFirmFileName[i] && uni_strlen (gSouFirmFileName[i]))
        {	
            readsize = 0;
            //ptr = FileOpenRead (gSouFirmFileName[i], NULL, &readsize);
			//==>            
            FILE *fp;
            fp = wfopen(gSouFirmFileName[i], "rb");
            fseek(fp, 0, SEEK_END);
            readsize = ftell(fp);
            fseek(fp, 0, SEEK_SET);
            ptr = malloc(readsize);
            fread(ptr, 1, readsize, fp);
            fclose(fp);
            //<==
            if (ptr)
            {	DBG("CCC 0x%p, readsize=%d\n", ptr, readsize);
                soudata[i] = ptr;
                sousize[i] = readsize;
            }
            else
            {	
                uni_printf (uni("錯誤，來源檔案 '%s' 沒有發現…\n"), gSouFirmFileName[i]);
                return (-1);
            }
            lastnum = i;
        }
    }

    // 進行壓縮
    if (gPackFlag)
    {	
        for (i = 0; i < dFwMax; i++)
        {
            if (sousize[i])
            {	
                tardata[i] = HuffmanPack ((U8*) soudata[i], sousize[i], 512, NULL, &tarsize[i]);
                // 檢查壓縮
                ptr = HuffmanUnpack ((U8*)tardata[i]);
                if (MemCmp (soudata[i], ptr, sousize[i]))
                {	
                    for (j = 0; j < sousize[i]; j++)
                    {
                        if (((U8*)soudata[i])[j] != ((U8*)ptr)[j]) break;
                    }
                    uni_printf (uni("錯誤，檔案 '%s' 解壓縮來源和目的不相符，程式錯誤，位置 0x%X…\n"), gSouFirmFileName[i], j);
                    Assert (0);
                }
                MemFree (ptr);
            }
        }
    }

    // 資料位置計算 (每個區塊做 512 Bytes 之定位)
    tolsize = sizeof (sFWInfo);
    tolsize = MathAlign (tolsize);
    
    for (i = 0; i < dFwMax; i++)
    {
        j = (gPackFlag ? tarsize[i] : sousize[i]);
        if (j)
        {
            gFwInfo.DataOffset[i]     = tolsize;                    // 資料之偏移位置 (0=無)
            gFwInfo.DataPackSize[i]   = j;                          // 壓縮後資料大小 (0=無)
            gFwInfo.DataUnPackSize[i] = sousize[i];                 // 未壓縮資料大小 (0=無)
            if (i != lastnum) j = MathAlign (j);                    // 最後有資料的編號 (不需要做 512 定位數量)
            else j = ((j + (4 - 1)) & (~(4 - 1)));
        }
        tolsize += j;
    }
    gFwInfo.TotalSize = tolsize;                                    // 檔案總大小
	DBG("DDD tolsize=%d\n", tolsize);	
    // 資料放入
    workptr = (U8*) MemMalloc (tolsize);
    MemZero (workptr, tolsize);
    MemCopy (workptr, &gFwInfo, sizeof (sFWInfo));
    for (i = 0; i < dFwMax; i++)
    {	
        if (sousize[i])
        {
            if (gPackFlag)
            {
                max = tarsize[i];
                u8ptr = workptr + gFwInfo.DataOffset[i];
                MemCopy (u8ptr, tardata[i], max);
            }
            else
            {	
                max = sousize[i];
                u8ptr = workptr + gFwInfo.DataOffset[i];
                MemCopy (u8ptr, soudata[i], max);
            }
            // XOR 運算數值
            if (gFwInfo.XorU32Val)
            {	DBG("EEE, 0x%08X\n", gFwInfo.XorU32Val);
                u32ptr = (U32*) u8ptr;
                u32val = gFwInfo.XorU32Val;
                if (max & 3) max = ((max + (4 - 1)) & (~(4 - 1)));
                max >>= 2;
                for (j = 0; j < max; j++)
                {
                    u32ptr[j] ^= (u32val + j);
                    u32val = ((u32val << 1) | (u32val >> 31));
                }
            }
        }
    }
    
    // 埋入 CheckSum 作業
    WriteCheckSum ((sFWInfo *) workptr, tolsize);
    MemCopy (&gFwInfo, workptr, sizeof (sFWInfo));
	
    // 資料寫出
    //FileOpenWrite (gWriteFileName, workptr, tolsize);
    {	
    	FILE *fp = wfopen(gWriteFileName, "wb");
    	fwrite(workptr, tolsize, 1, fp);
    	fclose(fp);
	}
	
	// 輸出紀錄檔案
	wchar_t txtname[256];
	FILE *file;
	wchar_t *pdot;
	
	wcscpy(txtname, gWriteFileName);
	pdot = wcsrchr(txtname, '.');
	wcscpy(pdot+1, L"txt");
	
	file = wfopen(txtname, "wt");
	if (gProgFileName)
	{
		fwprintf(file, L"來源韌體參考檔案 = %s (%d Bytes)\n",  gProgFileName, progsize);
	}
    for (i = 0; i < dFwMax; i++)
    {
        if (sousize[i])
        {
        	fwprintf(file, L"%-7ls 來源檔案 = %ls (%d Bytes)\n",  ImgMode[i], gSouFirmFileName[i], sousize[i]);
        }
    }
    fwprintf(file, L"目的檔案輸出檔名 = %ls\n", gWriteFileName);
    fwprintf(file, L"目的檔案輸出大小 = %d Bytes\n", tolsize);
    fwprintf(file, L"目的檔案之檢查碼 = 0x%.8X\n", gFwInfo.CheckSum);
	fclose(file);
	
    // 螢幕輸出
    uni_printf (uni("---------------------------------------------------------------------\n"));
    if (gProgFileName) uni_printf (uni("來源韌體參考檔案 = %ls (%d Bytes)\n"), gProgFileName, progsize);
    for (i = 0; i < dFwMax; i++)
    {
        if (sousize[i]) uni_printf (uni("%-7ls 來源檔案 = %ls (%d Bytes)\n"), ImgMode[i], gSouFirmFileName[i], sousize[i]);
    }
    uni_printf (uni("目的檔案輸出檔名 = %ls\n"), gWriteFileName);
    uni_printf (uni("目的檔案輸出大小 = %d Bytes\n"), tolsize);
    uni_printf (uni("目的檔案之檢查碼 = 0x%.8X\n"), gFwInfo.CheckSum);

    // 釋放記憶體
    MemFree (workptr);
    for (i = 0; i < dFwMax; i++)
    {
        if (tardata[i]) MemFree (tardata[i]);
        if (soudata[i]) MemFree (soudata[i]);
    }
    iniparser_freedict(ini);

    return (0);
}

